package com.qd.pay.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.cdqidi.constant.ConstantDto;
import com.cdqidi.dto.ApiResult;
import com.cdqidi.dto.CacheKey;
import com.cdqidi.exception.ApiException;
import com.cdqidi.util.RedisTemplateUtil;
import com.qd.pay.domain.OrderRefundDTO;
import com.qd.pay.model.OrderRefund;
import com.qd.pay.repository.OrderRefundRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;
import java.util.Optional;

/**
 * @author sjk
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class OrderRefundService {
    private static final String ORDER_ID = "order_id";
    private final OrderRefundRepository orderRefundRepository;
    @Resource
    private RedisTemplateUtil<OrderRefund> redisTemplateUtil;

    private static final String PREFIX_ID = "m_order_refund_rid_{0}";

    @Transactional(rollbackFor = Exception.class)
    public OrderRefund save(OrderRefund model) throws ApiException {
        try {
            if (!orderRefundRepository.save(model)) {
                throw new ApiException(ApiResult.error());
            }
        } finally {
            clearCache(model);
        }
        return model;
    }

    @Transactional(rollbackFor = Exception.class)
    public Boolean removeById(String rid) throws ApiException {
        final OrderRefund historyModel = Optional.ofNullable(getById(rid)).orElseThrow(() -> new ApiException("数据不存在,不能删除"));
        try {
            if (!orderRefundRepository.removeById(rid)) {
                throw new ApiException(ApiResult.error());
            }
            return true;
        } finally {
            clearCache(historyModel);
            historyModel.freeData();
        }
    }

    public boolean isExistsByOrderId(String orderId) {
        return orderRefundRepository.getBaseMapper().exists(new QueryWrapper<OrderRefund>().eq(ORDER_ID, orderId));
    }

    public boolean isExistsByOrderIdAndRefundNo(String orderId, Integer refundNo) {
        return orderRefundRepository.getBaseMapper().exists(new QueryWrapper<OrderRefund>().eq(ORDER_ID, orderId).eq("refund_no", refundNo));
    }

    public OrderRefund getOne(String outRefundNo) {
        return orderRefundRepository.getOne(new QueryWrapper<OrderRefund>().eq("out_refund_no", outRefundNo), false);
    }

    public OrderRefund getById(String rid) {
        String key = RedisTemplateUtil.getRedisCacheKey(PREFIX_ID, rid);
        return redisTemplateUtil.get(new CacheKey().setKey(key).setTimeout(ConstantDto.REDIS_TIME_OUT_DAY * 3), () -> orderRefundRepository.getById(rid), OrderRefund.class);
    }

    public IPage<OrderRefundDTO> page(Page<OrderRefundDTO> page, OrderRefund model) {
        QueryWrapper<OrderRefund> queryWrapper = new QueryWrapper<>(model);
        IPage<OrderRefund> iPage = orderRefundRepository.page(page.convert(this::dtoToModel), queryWrapper);
        return iPage.convert(this::modelToDto);
    }


    private void clearCache(OrderRefund model) {
        if (null == model) {
            return;
        }
        String key = RedisTemplateUtil.getRedisCacheKey(PREFIX_ID, model.getRid());
        redisTemplateUtil.deleteByKey(key);
    }

    public OrderRefundDTO modelToDto(OrderRefund model) {
        if (null == model) {
            return null;
        }
        OrderRefundDTO dto = new OrderRefundDTO();
        dto.setRid(model.getRid());
        dto.setOrderId(model.getOrderId());
        dto.setTransactionId(model.getTransactionId());
        dto.setOutRefundNo(model.getOutRefundNo());
        dto.setPayAmount(model.getPayAmount());
        dto.setRefundFee(model.getRefundFee());
        dto.setRefundDesc(model.getRefundDesc());
        dto.setIpAddress(model.getIpAddress());
        dto.setSendTime(model.getSendTime());
        dto.setPersonId(model.getPersonId());
        dto.setApCode(model.getApCode());
        dto.setRefundNo(model.getRefundNo());
        dto.setNotifyUrl(model.getNotifyUrl());
        return dto;
    }

    public OrderRefund dtoToModel(OrderRefundDTO dto) {
        if (null == dto) {
            return null;
        }
        OrderRefund model = new OrderRefund();
        model.setRid(dto.getRid());
        model.setOrderId(dto.getOrderId());
        model.setTransactionId(dto.getTransactionId());
        model.setOutRefundNo(dto.getOutRefundNo());
        model.setPayAmount(dto.getPayAmount());
        model.setRefundFee(dto.getRefundFee());
        model.setRefundDesc(dto.getRefundDesc());
        model.setIpAddress(dto.getIpAddress());
        model.setSendTime(dto.getSendTime());
        model.setPersonId(dto.getPersonId());
        model.setApCode(dto.getApCode());
        model.setRefundNo(dto.getRefundNo());
        model.setNotifyUrl(dto.getNotifyUrl());
        return model;
    }

    public OrderRefundDTO getOne(String transactionId, String outRefundNo) {
        QueryWrapper<OrderRefund> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("transaction_id", transactionId);
        queryWrapper.eq("out_refund_no", outRefundNo);
        queryWrapper.last("limit 1");
        return Optional.ofNullable(orderRefundRepository.getOne(queryWrapper, false)).map(this::modelToDto).orElse(null);
    }

    public List<OrderRefund> getListByOrderId(String orderId) {
        QueryWrapper<OrderRefund> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(ORDER_ID, orderId);
        final List<OrderRefund> list = orderRefundRepository.list(queryWrapper);
        queryWrapper.clear();
        return list;
    }
}